// 蜂窝蜜造平台生成代码，如手工更改，请添加到 .beeignore 忽略生成

package com.fowo.api.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fowo.api.common.annotaion.DataObjectType;
import com.fowo.api.common.config.CacheConfig;
import com.fowo.api.common.excel.CustomExcelExport;
import com.fowo.api.common.excel.CustomExcelHandler;
import com.fowo.api.common.excel.ExcelConfig;
import com.fowo.api.common.excel.TemplateModelBuildEventListener;
import com.fowo.api.common.model.ImportRow;
import com.fowo.api.common.model.JoinModel;
import com.fowo.api.common.model.OptionItem;
import com.fowo.api.common.model.RException;
import com.fowo.api.common.util.ContextHolder;
import com.fowo.api.common.util.DateUtils;
import com.fowo.api.common.util.ListUtils;
import com.fowo.api.common.util.ResponseUtils;
import com.fowo.api.common.util.SheetUtils;
import com.fowo.api.entity.WmsOrder;
import com.fowo.api.flow.entity.WorkFlow;
import com.fowo.api.flow.service.WorkFlowService;
import com.fowo.api.inventory.model.InventoryExchangeVo;
import com.fowo.api.inventory.model.InventoryOutboundVo;
import com.fowo.api.inventory.model.PatternEnum;
import com.fowo.api.inventory.model.SimpleInventoryItem;
import com.fowo.api.inventory.model.TargetTypeEnum;
import com.fowo.api.inventory.model.form.InventoryExchangeFormVo;
import com.fowo.api.inventory.model.form.InventoryOutboundFormVo;
import com.fowo.api.inventory.service.InventoryBusinessService;
import com.fowo.api.mapper.ShopInfoMapper;
import com.fowo.api.mapper.WarehouseMapper;
import com.fowo.api.mapper.WmsOrderItemMapper;
import com.fowo.api.mapper.WmsOrderMapper;
import com.fowo.api.model.shop.info.ShopInfoItemVo;
import com.fowo.api.model.shop.info.ShopInfoSearchParamPo;
import com.fowo.api.model.warehouse.WarehouseItemVo;
import com.fowo.api.model.warehouse.WarehouseSearchParamPo;
import com.fowo.api.model.wms.order.WmsOrderBatchStockOutAction;
import com.fowo.api.model.wms.order.WmsOrderExcelPo;
import com.fowo.api.model.wms.order.WmsOrderImportPo;
import com.fowo.api.model.wms.order.WmsOrderItemVo;
import com.fowo.api.model.wms.order.WmsOrderSearchParamPo;
import com.fowo.api.model.wms.order.WmsOrderVo;
import com.fowo.api.model.wms.order.constant.WmsOrderIsOperationEnums;
import com.fowo.api.model.wms.order.constant.WmsOrderLogisticsStatusEnums;
import com.fowo.api.model.wms.order.constant.WmsOrderOrderTypeEnums;
import com.fowo.api.model.wms.order.constant.WmsOrderStatusEnums;
import com.fowo.api.model.wms.order.item.WmsOrderItemItemVo;
import com.fowo.api.model.wms.order.item.WmsOrderItemSearchParamPo;
import com.fowo.api.service.WmsOrderItemService;
import com.fowo.api.service.WmsOrderService;
import com.fowo.api.sys.annotation.DataActivity;
import com.fowo.api.sys.component.ExecuteScriptEngine;
import com.fowo.api.sys.component.SysDataActivityAopHelper;
import com.fowo.api.sys.entity.SysFile;
import com.fowo.api.sys.entity.SysImportTemplate;
import com.fowo.api.sys.entity.enums.SysDataActivityAction;
import com.fowo.api.sys.model.NewSerialRequest;
import com.fowo.api.sys.model.SysDictAllItem;
import com.fowo.api.sys.service.FileService;
import com.fowo.api.sys.service.SysDictService;
import com.fowo.api.sys.service.SysImportTemplateService;
import com.fowo.api.sys.service.SysSerialService;
import com.fowo.api.user.model.JwtUserInfo;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

/**
 * 销售出库单(wms) 服务实现基类
 * @author 蜂窝蜜造平台 配置人：王阳阳，吕家傲
 */
@Slf4j
@DataObjectType(WmsOrder.class)
@DS("ds24")
public class WmsOrderBaseServiceImpl
  extends ServiceImpl<WmsOrderMapper, WmsOrder>
  implements WmsOrderService {

  /** 引用字段排序字段名转换信息 */
  public static final Map<String, String> SORT_FIELD_MAP = new HashMap<>() {
    {
      put("sidShopName", "si.`shop_name`");
      put("widName", "w.`name`");
    }
  };
  // 导出时单次查询最大记录数
  protected static final int EXPORT_QUERY_MAX_SIZE = 1000;
  // 支持导出的最大记录数(1048576 为 Excel 支持的最大行数)
  protected static final long EXPORT_MAX_SIZE = 1048575;

  /**
   * 服务自引用，用于调用服务方法时包括 AOP 处理
   */
  @Resource
  protected WmsOrderService self;

  @Resource
  protected WmsOrderItemService wmsOrderItemService;

  @Resource
  protected SysSerialService sysSerialService;

  @Resource
  private SysDictService sysDictService;

  @Resource
  protected ShopInfoMapper shopInfoMapper;

  @Resource
  protected WarehouseMapper warehouseMapper;

  @Resource
  protected FileService fileService;

  @Resource
  protected SysImportTemplateService importTemplateService;

  @Resource
  private CustomExcelExport customExcelExport;

  @Resource
  protected WorkFlowService workFlowService;

  @Resource
  protected InventoryBusinessService inventoryBusinessService;

  @Resource
  private ExecuteScriptEngine executeScriptEngine;

  @Autowired(required = false)
  protected WmsOrderBatchStockOutAction wmsOrderBatchStockOutAction;

  @Resource
  protected Validator validator;

  /**
   * 创建销售出库单(wms)
   * @param model 销售出库单(wms)
   * @return 新数据的主键
   */
  @DataActivity(action = SysDataActivityAction.Add)
  @Transactional(rollbackFor = Exception.class)
  @Override
  public Long create(WmsOrderVo model) throws Exception {
    JwtUserInfo currentUser = JwtUserInfo.fromHeader();
    WmsOrder entity = new WmsOrder();
    BeanUtils.copyProperties(model, entity);
    entity.setCreateTime(new Date());
    entity.setLastUpdateTime(new Date());
    if (currentUser != null) {
      entity.setCreateUser(currentUser.getUserId());
      entity.setLastUpdateUser(currentUser.getUserId());
    }
    // 填充序列号
    if (!StringUtils.hasText(entity.getWoNumber())) {
      entity.setWoNumber(
        sysSerialService.getNewSerial(
          new NewSerialRequest(null, "WmsOrder.woNumber")
        )
      );
    }
    if (this.save(entity)) {
      model.setId(entity.getId());
      updateAllChilds(model);
      return entity.getId();
    }
    throw new Exception("销售出库单(wms)保存失败");
  }

  /**
   * 更新所有子表
   * @param model 销售出库单(wms)
   */
  protected void updateAllChilds(WmsOrderVo model) throws Exception {
    if (model.getProductInfo() != null) {
      wmsOrderItemService.saveAllByParentId(
        model.getId(),
        model.getProductInfo()
      );
    }
  }

  /**
   * 更新销售出库单(wms)
   * @param model 销售出库单(wms)
   * @return 更新是否成功
   */
  @DataActivity(action = SysDataActivityAction.Modified)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean update(WmsOrderVo model) throws Exception {
    JwtUserInfo currentUser = JwtUserInfo.fromHeader();
    WmsOrder entity = this.getById(model.getId());
    if (entity == null) {
      throw new Exception("销售出库单(wms)不存在");
    }
    BeanUtils.copyProperties(
      model,
      entity,
      "id",
      "lastUpdateUser",
      "createUser",
      "lastUpdateTime",
      "createTime"
    );
    entity.setLastUpdateTime(new Date());
    if (currentUser != null) {
      entity.setLastUpdateUser(currentUser.getUserId());
    }
    if (this.updateById(entity)) {
      updateAllChilds(model);
      return true;
    }
    return false;
  }/**
   * 更新销售出库单(wms)（带空值）
   * @param model 销售出库单(wms)
   * @return 更新是否成功
   */

  @DataActivity(action = SysDataActivityAction.Modified)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean updateForEdit(WmsOrderVo model) throws Exception {
    JwtUserInfo currentUser = JwtUserInfo.fromHeader();
    WmsOrder entity = this.getById(model.getId());
    if (entity == null) {
      throw new Exception("销售出库单(wms)不存在");
    }
    model.setLastUpdateTime(new Date());
    if (currentUser != null) {
      model.setLastUpdateUser(currentUser.getUserId());
    }
    boolean isOk = new LambdaUpdateChainWrapper<>(baseMapper)
      .set(WmsOrder::getSid, model.getSid())
      .set(WmsOrder::getTargetCountry, model.getTargetCountry())
      .set(WmsOrder::getRecipient, model.getRecipient())
      .set(WmsOrder::getPhone, model.getPhone())
      .set(WmsOrder::getZipCode, model.getZipCode())
      .set(WmsOrder::getAddress, model.getAddress())
      .set(WmsOrder::getOrderBuyerNotes, model.getOrderBuyerNotes())
      .set(WmsOrder::getLastUpdateUser, model.getLastUpdateUser())
      .set(WmsOrder::getLastUpdateTime, model.getLastUpdateTime())
      .set(WmsOrder::getPkgFeeWeight, model.getPkgFeeWeight())
      .set(WmsOrder::getCity, model.getCity())
      .set(WmsOrder::getProvinceState, model.getProvinceState())
      .set(WmsOrder::getDistrictCounty, model.getDistrictCounty())
      .set(WmsOrder::getHouseNumber, model.getHouseNumber())
      .set(WmsOrder::getIsOperation, model.getIsOperation())
      .set(WmsOrder::getBuyerEmail, model.getBuyerEmail())
      .eq(WmsOrder::getId, model.getId())
      .update();
    if (isOk) {
      updateAllChilds(model);
    }
    return isOk;
  }

  /**
   * 是否走导出中心
   */
  @Override
  public boolean getBackgroundExportFlag(WmsOrderSearchParamPo search) {
    return false;
  }

  /**
   * 批量删除指定主键列表关联的所有子表数据(此方法不包括事务，必须由其它已包括事务的方法调用)
   */
  protected void batchDeleteChilds(List<Long> ids) throws Exception {
    // 处理子表字段 商品信息(productInfo) 对应的对象
    WmsOrderItemSearchParamPo productInfoSearchParam =
      new WmsOrderItemSearchParamPo();
    productInfoSearchParam.setDisableDataPremissions(true);
    productInfoSearchParam.setParentIdInList(ids);
    WmsOrderItemMapper localWmsOrderItemMapper = ContextHolder
      .getApplicationContext()
      .getBean(WmsOrderItemMapper.class);
    productInfoSearchParam.applySqlSegments();
    List<Long> productInfoIdList = localWmsOrderItemMapper.searchIds(
      productInfoSearchParam
    );
    if (!productInfoIdList.isEmpty()) {
      WmsOrderItemService localWmsOrderItemService = ContextHolder
        .getApplicationContext()
        .getBean(WmsOrderItemService.class);
      localWmsOrderItemService.batchDelete(productInfoIdList);
    }
  }

  /**
   * 删除销售出库单(wms)
   * @param id 销售出库单(wms)的主键
   * @return 删除是否成功
   */
  @DataActivity(action = SysDataActivityAction.Del)
  @Override
  public boolean delete(Long id) throws Exception {
    batchDeleteChilds(Collections.singletonList(id));
    return this.removeById(id);
  }

  /**
   * 批量删除销售出库单(wms)
   * @param ids 销售出库单(wms)的主键列表
   * @return 删除是否成功
   */
  @DataActivity(action = SysDataActivityAction.Del)
  @Override
  public boolean batchDelete(List<Long> ids) throws Exception {
    batchDeleteChilds(ids);

    int count = 0;
    for (int i = 0; i < ids.size(); i += 2000) {
      count +=
        baseMapper.deleteBatchIds(
          ids.stream().skip(i).limit(2000).collect(Collectors.toList())
        );
    }
    return count > 0;
  }

  /**
   * 导入单行处理
   * @param row 要导入的行
   * @param rowNumber 所在行号
   * @param vo 输出VO,可空
   * @param variables 变量池，用于在一次导入过程中保存临时信息
   * @param allowOverrides 允许覆盖
   * @return 导入行对象
   */
  protected ImportRow<WmsOrderImportPo> excelToImportRow(
    WmsOrderImportPo row,
    Integer rowNumber,
    WmsOrderVo vo,
    Map<String, Object> variables,
    boolean allowOverrides
  ) {
    ImportRow<WmsOrderImportPo> ir = new ImportRow<WmsOrderImportPo>();
    ir.setRowNumber(rowNumber);
    ir.setRow(row);
    if (SheetUtils.isAllFieldsEmpty(row)) {
      ir.setEmptyRow(true);
      ir.addError("", "空行");
      return ir;
    }
    final Set<ConstraintViolation<WmsOrderImportPo>> validate =
      validator.validate(row);
    boolean isOutputVo = vo != null;
    if (!isOutputVo) {
      vo = new WmsOrderVo();
    }
    BeanUtils.copyProperties(row, vo);
    // 收集基本校验错误
    ir.initErrors(validate, WmsOrderImportPo.class);

    // 一般数据处理
    vo.setParentNavSellOrder(SheetUtils.tryToLong(row.getParentNavSellOrder()));
    if (StringUtils.hasText(row.getStatus())) {
      vo.setStatus(WmsOrderStatusEnums.toValue(row.getStatus()));
      if (vo.getStatus() == null) {
        ir.addError(
          "status",
          "状态只能是：“物流下单”, “发货中”, “已发货”, “已删除”, “已出库”"
        );
      }
    }
    vo.setDeliveredAt(SheetUtils.tryToDateTime(row.getDeliveredAt()));
    vo.setLogisticsEstimatedFreight(
      SheetUtils.tryToDecimal(row.getLogisticsEstimatedFreight())
    );
    vo.setLogisticsFreight(SheetUtils.tryToDecimal(row.getLogisticsFreight()));
    vo.setStockDeliveredAt(SheetUtils.tryToDateTime(row.getStockDeliveredAt()));
    if (StringUtils.hasText(row.getIsCheck())) {
      List<SysDictAllItem> isCheckItems =
        (List<SysDictAllItem>) variables.computeIfAbsent(
          "isCheck",
          n -> sysDictService.getDictItems("SCM00008")
        );
      WmsOrderVo finalVo = vo;
      isCheckItems
        .stream()
        .filter(i -> i.getItemText().equals(row.getIsCheck()))
        .findFirst()
        .ifPresentOrElse(
          i -> finalVo.setIsCheck(i.getItemValue()),
          () ->
            ir.addError(
              "isCheck",
              String.format(
                "必须为 %s 中之一",
                isCheckItems
                  .stream()
                  .map(SysDictAllItem::getItemText)
                  .collect(Collectors.joining(", "))
              )
            )
        );
    }
    if (StringUtils.hasText(row.getIsWeigh())) {
      List<SysDictAllItem> isWeighItems =
        (List<SysDictAllItem>) variables.computeIfAbsent(
          "isWeigh",
          n -> sysDictService.getDictItems("SCM00008")
        );
      WmsOrderVo finalVo = vo;
      isWeighItems
        .stream()
        .filter(i -> i.getItemText().equals(row.getIsWeigh()))
        .findFirst()
        .ifPresentOrElse(
          i -> finalVo.setIsWeigh(i.getItemValue()),
          () ->
            ir.addError(
              "isWeigh",
              String.format(
                "必须为 %s 中之一",
                isWeighItems
                  .stream()
                  .map(SysDictAllItem::getItemText)
                  .collect(Collectors.joining(", "))
              )
            )
        );
    }
    if (StringUtils.hasText(row.getIsSurfacePrint())) {
      List<SysDictAllItem> isSurfacePrintItems =
        (List<SysDictAllItem>) variables.computeIfAbsent(
          "isSurfacePrint",
          n -> sysDictService.getDictItems("SCM00008")
        );
      WmsOrderVo finalVo = vo;
      isSurfacePrintItems
        .stream()
        .filter(i -> i.getItemText().equals(row.getIsSurfacePrint()))
        .findFirst()
        .ifPresentOrElse(
          i -> finalVo.setIsSurfacePrint(i.getItemValue()),
          () ->
            ir.addError(
              "isSurfacePrint",
              String.format(
                "必须为 %s 中之一",
                isSurfacePrintItems
                  .stream()
                  .map(SysDictAllItem::getItemText)
                  .collect(Collectors.joining(", "))
              )
            )
        );
    }
    if (StringUtils.hasText(row.getIsorderPrint())) {
      List<SysDictAllItem> isorderPrintItems =
        (List<SysDictAllItem>) variables.computeIfAbsent(
          "isorderPrint",
          n -> sysDictService.getDictItems("SCM00008")
        );
      WmsOrderVo finalVo = vo;
      isorderPrintItems
        .stream()
        .filter(i -> i.getItemText().equals(row.getIsorderPrint()))
        .findFirst()
        .ifPresentOrElse(
          i -> finalVo.setIsorderPrint(i.getItemValue()),
          () ->
            ir.addError(
              "isorderPrint",
              String.format(
                "必须为 %s 中之一",
                isorderPrintItems
                  .stream()
                  .map(SysDictAllItem::getItemText)
                  .collect(Collectors.joining(", "))
              )
            )
        );
    }
    vo.setPkgLength(SheetUtils.tryToDecimal(row.getPkgLength()));
    vo.setPkgHeight(SheetUtils.tryToDecimal(row.getPkgHeight()));
    vo.setPkgRealWeight(SheetUtils.tryToDecimal(row.getPkgRealWeight()));
    vo.setPkgWeight(SheetUtils.tryToDecimal(row.getPkgWeight()));
    if (StringUtils.hasText(row.getOrderType())) {
      vo.setOrderType(WmsOrderOrderTypeEnums.toValue(row.getOrderType()));
      if (vo.getOrderType() == null) {
        ir.addError(
          "orderType",
          "订单类型只能是：“一单一件”, “多品多件【原一单多件】”, “单品多件”"
        );
      }
    }
    vo.setPkgVolume(SheetUtils.tryToDecimal(row.getPkgVolume()));
    if (StringUtils.hasText(row.getLogisticsStatus())) {
      vo.setLogisticsStatus(
        WmsOrderLogisticsStatusEnums.toValue(row.getLogisticsStatus())
      );
      if (vo.getLogisticsStatus() == null) {
        ir.addError(
          "logisticsStatus",
          "物流下单状态只能是：“待导入”, “物流待下单”, “ 物流下单中”, “下单异常”, “ 下单完成”, “待海外仓下单”, “海外仓下单中”, “待导入国内物流”, “物流取消中”, “物流取消异常”, “物流取消完成”"
        );
      }
    }
    vo.setPkgWidth(SheetUtils.tryToDecimal(row.getPkgWidth()));
    vo.setPkgFeeWeight(SheetUtils.tryToDecimal(row.getPkgFeeWeight()));
    if (StringUtils.hasText(row.getIsOperation())) {
      vo.setIsOperation(WmsOrderIsOperationEnums.toValue(row.getIsOperation()));
      if (vo.getIsOperation() == null) {
        ir.addError("isOperation", "是否操作库存只能是：“已操作”, “未操作”");
      }
    }
    vo.setWoId(SheetUtils.tryToInteger(row.getWoId()));
    // 处理关联字段“店铺”
    if (
      !SheetUtils.isBlank(row.getSidShopName()) &&
      SheetUtils.isBlank(row.getSid())
    ) {
      ShopInfoSearchParamPo sidSearchParam = new ShopInfoSearchParamPo();
      sidSearchParam.setLimit(2); // 最大只返回二行记录
      sidSearchParam.setShopNameEq(SheetUtils.trim(row.getSidShopName()));
      sidSearchParam.applySqlSegments();
      List<ShopInfoItemVo> sidMatches = shopInfoMapper.search(sidSearchParam);
      if (sidMatches.size() == 0) {
        ir.addError("sidShopName", "未能在店铺中找到匹配的数据");
      } else if (sidMatches.size() > 1) {
        ir.addError("sidShopName", "关联不唯一，在店铺中找到多个匹配的数据");
      } else {
        vo.setSid(sidMatches.get(0).getId());
      }
    }
    // 处理关联字段“仓库”
    if (
      !SheetUtils.isBlank(row.getWidName()) && SheetUtils.isBlank(row.getWid())
    ) {
      WarehouseSearchParamPo widSearchParam = new WarehouseSearchParamPo();
      widSearchParam.setLimit(2); // 最大只返回二行记录
      widSearchParam.setNameEq(SheetUtils.trim(row.getWidName()));
      widSearchParam.applySqlSegments();
      List<WarehouseItemVo> widMatches = warehouseMapper.search(widSearchParam);
      if (widMatches.size() == 0) {
        ir.addError("widName", "未能在仓库即时库存中找到匹配的数据");
      } else if (widMatches.size() > 1) {
        ir.addError(
          "widName",
          "关联不唯一，在仓库即时库存中找到多个匹配的数据"
        );
      } else {
        vo.setWid(widMatches.get(0).getId());
      }
    }

    return ir;
  }

  /**
   * 导入预览
   * @param sysFile 已上传到系统的文件
   * @param templateId 要使用的模版编号
   * @param allowOverrides 允许覆盖
   */
  @Override
  public List<ImportRow<WmsOrderImportPo>> importPreview(
    SysFile sysFile,
    Long templateId,
    boolean allowOverrides
  ) throws Exception {
    SysImportTemplate importTemplate = null;
    if (templateId != null && templateId > 0) {
      importTemplate = importTemplateService.getById(templateId);
      if (importTemplate == null) {
        throw new RException("指定的模版不可用！");
      }
    }
    Map<String, Object> variables = new HashMap<>();

    // 标记由模版直接导入的字段集
    if (importTemplate != null) {
      variables.put(
        "IMPORT_FIELDS",
        importTemplate
          .getSetting()
          .getMappings()
          .stream()
          .map(SysImportTemplate.Mapping::getField)
          .collect(Collectors.toSet())
      );
    }
    try (InputStream in = fileService.read(sysFile)) {
      List<ImportRow<WmsOrderImportPo>> rows = new ArrayList<>();

      // 读取 Excel 到 rows
      EasyExcel
        .read(in)
        .useDefaultListener(false)
        .registerReadListener(
          new TemplateModelBuildEventListener<>(
            WmsOrderImportPo.class,
            importTemplate
          ) {
            @Override
            public void invokeRow(WmsOrderImportPo row, AnalysisContext cxt) {
              WmsOrderVo vo = new WmsOrderVo();
              ImportRow<WmsOrderImportPo> ir = excelToImportRow(
                row,
                cxt.readRowHolder().getRowIndex(),
                vo,
                variables,
                allowOverrides
              );
              if (ir.isEmptyRow()) {
                return;
              }
              if (allowOverrides) {
                // FIXME: 未在平台上配置此对象《作为导入唯一识别》的《逻辑分组》配置，无法处理更新模式
              }
              rows.add(ir);
            }
          }
        )
        .sheet()
        .doRead();

      return rows;
    }
  }

  /**
   * 完成导入
   * @param rows 预导入的行信息
   */
  @DataActivity(action = SysDataActivityAction.Import)
  @Transactional(rollbackFor = Exception.class)
  @Override
  public void importDone(
    List<ImportRow<WmsOrderImportPo>> rows,
    Long templateId
  ) throws Exception {
    SysImportTemplate importTemplate = null;
    if (templateId != null && templateId > 0) {
      importTemplate = importTemplateService.getById(templateId);
      if (importTemplate == null) {
        throw new RException("指定的模版不可用！");
      }
    }
    String sysImportBatchNo = StrUtil.concat(
      true,
      DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_MS_PATTERN),
      IdUtil.nanoId(4)
    );
    List<Long> importedIdList = new ArrayList<>();
    SysDataActivityAopHelper.clear();
    final SysDataActivityAopHelper.DataActivityAopContext context =
      SysDataActivityAopHelper.getOrCreateContext();
    Map<String, Object> variables = new HashMap<>();

    // 标记由模版直接导入的字段集
    if (importTemplate != null) {
      variables.put(
        "IMPORT_FIELDS",
        importTemplate
          .getSetting()
          .getMappings()
          .stream()
          .map(SysImportTemplate.Mapping::getField)
          .collect(Collectors.toSet())
      );
    }
    for (int i = 0; i < rows.size(); i++) {
      ImportRow<WmsOrderImportPo> row = rows.get(i);
      Long updateId = row.getUpdateId();
      WmsOrderVo vo = new WmsOrderVo();
      row =
        excelToImportRow(row.getRow(), row.getRowNumber(), vo, variables, true);
      if (row.getErrors() != null && row.getErrors().size() > 0) {
        throw new RException(
          String.format(
            "第%d行（Excel第%d行）数据验证错误：%s",
            i + 1,
            row.getRowNumber(),
            row.getJoinErrorMessage()
          )
        );
      }
      if (updateId != null) {
        vo.setId(updateId);
      }
      // 重建"销售出库单号"
      if (
        importTemplate != null &&
        importTemplate
          .getSetting()
          .getMappings()
          .stream()
          .anyMatch(m ->
            Boolean.TRUE.equals(m.getNeedRecreate()) &&
            "woNumber".equals(m.getField())
          )
      ) {
        vo.setWoNumber(
          sysSerialService.getNewSerial(
            new NewSerialRequest(null, "WmsOrder.woNumber")
          )
        );
      }

      SheetUtils.setSysImportTemplateName(
        vo,
        null == importTemplate ? "默认模板" : importTemplate.getTitle()
      );
      SheetUtils.setSysImportBatchNo(vo, sysImportBatchNo);
      if (updateId == null) {
        importedIdList.add(create(vo));
      } else {
        self.update(vo);
        importedIdList.add(vo.getId());
      }
    }
    context.getIdList().addAll(importedIdList);
  }

  /**
   * 导出
   * @param templateId 使用模版（可以是 null 或 0 表示系统默认导出模版）
   * @param search 查询条件
   */
  @DataActivity(action = SysDataActivityAction.Export)
  @Override
  public void export(
    Long templateId,
    WmsOrderSearchParamPo search,
    HttpServletResponse response
  ) throws Exception {
    if (templateId != null && templateId > 0) {
      SysImportTemplate sysImportTemplate = importTemplateService.getById(
        templateId
      );
      if (sysImportTemplate == null) {
        throw new RException("所选的导出模版不可用");
      }
      CustomExcelExport.CustomExcelExportOptions exportOptions =
        new CustomExcelExport.CustomExcelExportOptions();
      exportOptions.setImportTemplate(sysImportTemplate);
      exportOptions.setSearchParam(search);
      exportOptions.setMainService(this);
      exportOptions.addFieldMappingOption(
        "status",
        new CustomExcelExport.FieldMappingOption()
          .setConverter((o, r) -> WmsOrderStatusEnums.toLabel((String) o))
      );
      exportOptions.addFieldMappingOption(
        "sid",
        new CustomExcelExport.FieldMappingOption()
          .setConverter((o, r) ->
            String.valueOf(((WmsOrderItemVo) r).getSidShopName())
          )
      );
      exportOptions.addFieldMappingOption(
        "wid",
        new CustomExcelExport.FieldMappingOption()
          .setConverter((o, r) ->
            String.valueOf(((WmsOrderItemVo) r).getWidName())
          )
      );
      exportOptions.addFieldMappingOption(
        "isCheck",
        new CustomExcelExport.FieldMappingOption().setDictCode("SCM00008")
      );
      exportOptions.addFieldMappingOption(
        "isWeigh",
        new CustomExcelExport.FieldMappingOption().setDictCode("SCM00008")
      );
      exportOptions.addFieldMappingOption(
        "isSurfacePrint",
        new CustomExcelExport.FieldMappingOption().setDictCode("SCM00008")
      );
      exportOptions.addFieldMappingOption(
        "isorderPrint",
        new CustomExcelExport.FieldMappingOption().setDictCode("SCM00008")
      );
      exportOptions.addFieldMappingOption(
        "orderType",
        new CustomExcelExport.FieldMappingOption()
          .setConverter((o, r) -> WmsOrderOrderTypeEnums.toLabel((String) o))
      );
      exportOptions.addFieldMappingOption(
        "logisticsStatus",
        new CustomExcelExport.FieldMappingOption()
          .setConverter((o, r) ->
            WmsOrderLogisticsStatusEnums.toLabel((String) o)
          )
      );
      exportOptions.addFieldMappingOption(
        "isOperation",
        new CustomExcelExport.FieldMappingOption()
          .setConverter((o, r) -> WmsOrderIsOperationEnums.toLabel((String) o))
      );
      exportOptions.addStringFields(
        "woNumber",
        "orderNumber",
        "waveOrder",
        "status",
        "platformOrderNo",
        "tagNames",
        "sidShopName",
        "siteText",
        "platformName",
        "deliverer",
        "targetCountry",
        "recipientTaxNo",
        "waybillNo",
        "trackingNo",
        "widName",
        "isCheck",
        "isWeigh",
        "isSurfacePrint",
        "isorderPrint",
        "orderType",
        "recipient",
        "phone",
        "zipCode",
        "address",
        "orderOriginAmount",
        "deliverDeadline",
        "orderCustomerServiceNotes",
        "orderBuyerNotes",
        "processSn",
        "orderFrom",
        "batchNo",
        "picker",
        "logisticsStatus",
        "logisticsMessage",
        "logisticsProviderName",
        "logisticsTypeName",
        "isOperation",
        "buyerEmail"
      );

      String fileName = String.format(
        "销售出库单(wms)(%s).xlsx",
        DateUtils.toString(null, DateUtils.PATTERN_DATE_TIME)
      );
      ResponseUtils.setAttachmentFileName(response, fileName);
      customExcelExport.run(exportOptions, response.getOutputStream());
      return;
    }
    List<SysDictAllItem> isCheckItems = sysDictService.getDictItems("SCM00008");
    List<SysDictAllItem> isWeighItems = sysDictService.getDictItems("SCM00008");
    List<SysDictAllItem> isSurfacePrintItems = sysDictService.getDictItems(
      "SCM00008"
    );
    List<SysDictAllItem> isorderPrintItems = sysDictService.getDictItems(
      "SCM00008"
    );
    search.setPageSize(EXPORT_QUERY_MAX_SIZE);
    int current = 1;
    List<WmsOrderExcelPo> items = new ArrayList<WmsOrderExcelPo>();
    while (true) {
      search.setCurrent(current);
      search.setSelectFields(Collections.singletonList("@export"));
      Page<WmsOrderItemVo> page = this.pageSearch(search);
      if (page.getTotal() > EXPORT_MAX_SIZE) {
        throw new RException("导出记录数超出限制！");
      }
      List<WmsOrderItemVo> list = page.getRecords();
      if (list.isEmpty()) {
        break;
      }
      for (WmsOrderItemVo item : list) {
        WmsOrderExcelPo excel = new WmsOrderExcelPo();
        BeanUtils.copyProperties(item, excel);
        excel.setStatus(WmsOrderStatusEnums.toLabel(item.getStatus()));
        if (item.getIsCheck() != null) {
          isCheckItems
            .stream()
            .filter(i -> i.getItemValue().equals(item.getIsCheck()))
            .findFirst()
            .ifPresent(i -> excel.setIsCheck(i.getItemText()));
        }
        if (item.getIsWeigh() != null) {
          isWeighItems
            .stream()
            .filter(i -> i.getItemValue().equals(item.getIsWeigh()))
            .findFirst()
            .ifPresent(i -> excel.setIsWeigh(i.getItemText()));
        }
        if (item.getIsSurfacePrint() != null) {
          isSurfacePrintItems
            .stream()
            .filter(i -> i.getItemValue().equals(item.getIsSurfacePrint()))
            .findFirst()
            .ifPresent(i -> excel.setIsSurfacePrint(i.getItemText()));
        }
        if (item.getIsorderPrint() != null) {
          isorderPrintItems
            .stream()
            .filter(i -> i.getItemValue().equals(item.getIsorderPrint()))
            .findFirst()
            .ifPresent(i -> excel.setIsorderPrint(i.getItemText()));
        }
        excel.setOrderType(WmsOrderOrderTypeEnums.toLabel(item.getOrderType()));
        excel.setLogisticsStatus(
          WmsOrderLogisticsStatusEnums.toLabel(item.getLogisticsStatus())
        );
        excel.setIsOperation(
          WmsOrderIsOperationEnums.toLabel(item.getIsOperation())
        );

        items.add(excel);
      }
      if (list.size() < EXPORT_QUERY_MAX_SIZE) {
        break;
      }
      current++;
    }

    String fileName = String.format(
      "销售出库单(wms)(%s).xlsx",
      DateUtils.toString(null, DateUtils.PATTERN_DATE_TIME)
    );
    ResponseUtils.setAttachmentFileName(response, fileName);
    EasyExcel
      .write(response.getOutputStream())
      .registerWriteHandler(new CustomExcelHandler())
      .sheet()
      .head(WmsOrderExcelPo.class)
      .doWrite(items);
  }

  /**
   * 通过系统单号查询销售出库单(wms)主键(重复时返回最新的主键)
   */
  @Override
  public Long getIdByOrderNumber(String orderNumber) {
    return this.baseMapper.getIdByOrderNumber(orderNumber);
  }

  /**
   * 通过系统单号查询销售出库单(wms)多主键(重复时返回最新的主键)
   */
  @Override
  public List<Long> getIdsByOrderNumber(List<String> list) {
    return this.baseMapper.getIdsByOrderNumber(list);
  }

  /**
   * 通过销售出库单(wms)主键查询系统单号
   */
  @Override
  public String getOrderNumberById(Long id) {
    return this.baseMapper.getOrderNumberById(id);
  }

  /**
   * 通过销售出库单(wms)主键查询系统单号列表
   */
  @Override
  public List<String> getOrderNumberByIds(List<Long> ids) {
    List<Map<String, Object>> maps = this.baseMapper.getOrderNumberByIds(ids);
    // 将返回重新排列为输入相同顺序
    return ids
      .stream()
      .map(id -> {
        Optional<Map<String, Object>> optionalMap = maps
          .stream()
          .filter(map -> id.equals(map.get("id")))
          .findFirst();
        return optionalMap
          .map(stringObjectMap -> (String) stringObjectMap.get("orderNumber"))
          .orElse(null);
      })
      .collect(Collectors.toList());
  }

  /**
   * 获取详情
   * @param id 销售出库单(wms)的主键
   */
  @DataActivity(action = SysDataActivityAction.View)
  @Override
  public WmsOrderVo getVoById(Long id) throws Exception {
    WmsOrderVo vo = this.baseMapper.selectVoById(id);
    if (vo == null) {
      return null;
    }

    WmsOrderItemSearchParamPo productInfoSearchParamPo =
      new WmsOrderItemSearchParamPo();
    productInfoSearchParamPo.setParentId(id);
    // 禁用通用数据权限过滤
    productInfoSearchParamPo.setDisableDataPremissions(true);
    productInfoSearchParamPo.getExtendData().put("queryMode", "sub");
    productInfoSearchParamPo.getExtendData().put("queryParent", "WmsOrder");
    productInfoSearchParamPo.applySqlSegments();
    vo.setProductInfo(wmsOrderItemService.search(productInfoSearchParamPo));

    return vo;
  }

  /**
   * 主列表上要附加“商品信息”子表的部分字段
   * @param items 项目列表
   * @param sort 子表排序
   */
  protected void fillPartOfProductInfo(
    List<WmsOrderItemVo> items,
    String sort
  ) {
    WmsOrderItemSearchParamPo productInfoSearchParamPo =
      new WmsOrderItemSearchParamPo();
    productInfoSearchParamPo.setSort(sort);
    productInfoSearchParamPo.setSelectFields(
      List.of(
        "parentId",
        "productId",
        "sku",
        "img",
        "sellerSku",
        "stockCost",
        "distributionSituation",
        "orderSettlementTime",
        "referenceId"
      )
    );
    productInfoSearchParamPo.setParentIdInList(
      items.stream().map(WmsOrderItemVo::getId).collect(Collectors.toList())
    );
    // 禁用通用数据权限过滤
    productInfoSearchParamPo.setDisableDataPremissions(true);
    wmsOrderItemService
      .search(productInfoSearchParamPo)
      .forEach(productInfo -> {
        WmsOrderItemVo item = ListUtils.find(
          items,
          i -> Objects.equals(i.getId(), productInfo.getParentId())
        );
        if (item == null) return;
        if (item.getProductInfoProductId() == null) {
          item.setProductInfoProductId(new ArrayList<>());
        }
        item.getProductInfoProductId().add(productInfo.getProductId());

        if (item.getProductInfoSku() == null) {
          item.setProductInfoSku(new ArrayList<>());
        }
        item.getProductInfoSku().add(productInfo.getSku());

        if (item.getProductInfoImg() == null) {
          item.setProductInfoImg(new ArrayList<>());
        }
        item.getProductInfoImg().add(productInfo.getImg());

        if (item.getProductInfoSellerSku() == null) {
          item.setProductInfoSellerSku(new ArrayList<>());
        }
        item.getProductInfoSellerSku().add(productInfo.getSellerSku());

        if (item.getProductInfoStockCost() == null) {
          item.setProductInfoStockCost(new ArrayList<>());
        }
        item.getProductInfoStockCost().add(productInfo.getStockCost());

        if (item.getProductInfoDistributionSituation() == null) {
          item.setProductInfoDistributionSituation(new ArrayList<>());
        }
        item
          .getProductInfoDistributionSituation()
          .add(productInfo.getDistributionSituation());

        if (item.getProductInfoOrderSettlementTime() == null) {
          item.setProductInfoOrderSettlementTime(new ArrayList<>());
        }
        item
          .getProductInfoOrderSettlementTime()
          .add(productInfo.getOrderSettlementTime());

        if (item.getProductInfoReferenceId() == null) {
          item.setProductInfoReferenceId(new ArrayList<>());
        }
        item.getProductInfoReferenceId().add(productInfo.getReferenceId());
      });
  }

  /**
   * 分页查询销售出库单(wms)
   * @param search 查询条件
   * @return 销售出库单(wms)分页查询结果
   */
  @Override
  public Page<WmsOrderItemVo> pageSearch(WmsOrderSearchParamPo search) {
    Page<WmsOrderItemVo> page = new Page<>();
    if (
      Objects.nonNull(search.getWfStatus()) &&
      StringUtils.hasText(search.getFormName())
    ) {
      List<WorkFlow> workFlowList = workFlowService.queryWfListByStatus(
        search.getWfStatus(),
        search.getFormName()
      );
      if (CollectionUtils.isEmpty(workFlowList)) {
        return page;
      }
      List<Long> ids = workFlowList
        .stream()
        .map(WorkFlow::getRecordId)
        .collect(Collectors.toList());
      if (CollectionUtils.isEmpty(ids)) {
        return page;
      }
      search.setSelectedIds(ids);
    }
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    page = this.baseMapper.pageSearch(search.toPage(), search);
    List<Long> recordIds = page
      .getRecords()
      .stream()
      .map(WmsOrderItemVo::getId)
      .collect(Collectors.toList());
    if (CollectionUtils.isEmpty(recordIds)) {
      return page;
    }
    List<WorkFlow> workFlows = workFlowService.queryWfList(
      recordIds,
      Collections.singletonList(search.getFormName())
    );
    if (CollectionUtils.isEmpty(workFlows)) {
      return page;
    }
    Map<Long, Integer> flowMap = workFlows
      .stream()
      .collect(Collectors.toMap(WorkFlow::getRecordId, WorkFlow::getWfStatus));
    page
      .getRecords()
      .stream()
      .forEach(item -> {
        if (!flowMap.containsKey(item.getId())) {
          return;
        }
        item.setWfStatus(flowMap.get(item.getId()));
      });
    return page;
  }

  /**
   * 销售出库单(wms)快速查询选项(有缓存)
   * @param search 查询条件
   * @return 选项结果
   */
  @Override
  @Cacheable(
    value = CacheConfig.FAST,
    key = "'WmsOrderOptions::' + @userInfo.userTypeAndId + '::' + #search.keyword"
  )
  public List<OptionItem<WmsOrderItemVo>> searchOptions(
    WmsOrderSearchParamPo search
  ) {
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    return this.baseMapper.searchOptions(search);
  }

  /**
   * 列表查询销售出库单(wms)
   * @param search 查询条件
   * @return 销售出库单(wms)列表查询结果
   */
  @Override
  public List<WmsOrderItemVo> search(WmsOrderSearchParamPo search) {
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    return this.baseMapper.search(search);
  }

  /**
   * 查询销售出库单(wms)最后更新时间
   * @param search 查询条件
   * @return 销售出库单(wms)最后更新时间
   */
  @Override
  public Date searchLastUpdateTime(WmsOrderSearchParamPo search) {
    return this.baseMapper.searchLastUpdateTime(search);
  }

  /**
   * 销售出库
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了销售出库操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void salesOutWarehouse(List<Long> ids) throws Exception {
    List<Long> list = Convert.toList(Long.class, ids);
    for (Long id : list) {
      WmsOrderVo vo = getVoById(id);
      InventoryOutboundFormVo formVo = prepareSalesOutWarehouse(vo);
      inventoryBusinessService.outbound(formVo);
      // 更新成功状态
      WmsOrder updateStatusEntity = new WmsOrder();
      updateStatusEntity.setId(id);
      updateStatusEntity.setIsOperation("1");
      updateById(updateStatusEntity);
    }
  }

  /**
   * 准备用于 销售出库 的参数
   */
  protected InventoryOutboundFormVo prepareSalesOutWarehouse(WmsOrderVo vo)
    throws Exception {
    if (!"0".equals(vo.getIsOperation())) {
      throw new Exception("当前单据状态不可进行此操作！");
    }
    InventoryOutboundFormVo formVo = new InventoryOutboundFormVo();
    if (ReflectUtil.hasField(WmsOrderVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setSupportNegative(true);
    formVo.setFrom(TargetTypeEnum.Normal);
    formVo.setFormNum(vo.getWoNumber());
    if (ObjectUtils.isEmpty(vo.getDeliverer())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getDeliverer());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("仓库 为空");
    }
    formVo.setStockId(vo.getWid());
    formVo.setModel(PatternEnum.FIFO);
    for (WmsOrderItemItemVo wmsOrderItem : vo.getProductInfo()) {
      SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
      inventoryItem.setId(wmsOrderItem.getProductId());
      InventoryOutboundVo outboundItem = new InventoryOutboundVo();
      outboundItem.setItem(inventoryItem);
      outboundItem.setQty(
        String.valueOf(wmsOrderItem.getCount()).equals("null")
          ? BigDecimal.valueOf(0)
          : BigDecimal.valueOf(wmsOrderItem.getCount())
      );
      outboundItem.setCustomId(vo.getId());
      outboundItem.setCustomBdId(wmsOrderItem.getId());
      formVo.add(outboundItem);
    }
    return formVo;
  }

  /**
   * 订单(取消锁库存_即时)
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了订单(取消锁库存_即时)操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void cancelLocksInventory(Long id) throws Exception {
    WmsOrderVo vo = getVoById(id);
    InventoryExchangeFormVo formVo = prepareCancelLocksInventory(vo);
    inventoryBusinessService.exchange(formVo);
  }

  /**
   * 准备用于 订单(取消锁库存_即时) 的参数
   */
  protected InventoryExchangeFormVo prepareCancelLocksInventory(WmsOrderVo vo)
    throws Exception {
    InventoryExchangeFormVo formVo = new InventoryExchangeFormVo();
    if (ReflectUtil.hasField(WmsOrderVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setFrom(TargetTypeEnum.Lock);
    formVo.setTo(TargetTypeEnum.Normal);
    formVo.setFormNum(vo.getWoNumber());
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("出仓库 为空");
    }
    formVo.setFromStockId(vo.getWid());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("入仓库 为空");
    }
    formVo.setToStockId(vo.getWid());
    formVo.setModel(PatternEnum.FIFO);
    for (WmsOrderItemItemVo wmsOrderItem : vo.getProductInfo()) {
      SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
      inventoryItem.setId(wmsOrderItem.getProductId());
      InventoryExchangeVo exchangeItem = new InventoryExchangeVo();
      exchangeItem.setItem(inventoryItem);
      exchangeItem.setQty(
        String.valueOf(wmsOrderItem.getCount()).equals("null")
          ? BigDecimal.valueOf(0)
          : BigDecimal.valueOf(wmsOrderItem.getCount())
      );
      exchangeItem.setCustomId(vo.getId());
      exchangeItem.setCustomBdId(wmsOrderItem.getId());
      formVo.add(exchangeItem);
    }
    return formVo;
  }

  /**
   * 订单（取消锁库存_仓位）
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了订单（取消锁库存_仓位）操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void cancelLockpInventory(Long id) throws Exception {
    WmsOrderVo vo = getVoById(id);
    InventoryExchangeFormVo formVo = prepareCancelLockpInventory(vo);
    inventoryBusinessService.exchange(formVo);
  }

  /**
   * 准备用于 订单（取消锁库存_仓位） 的参数
   */
  protected InventoryExchangeFormVo prepareCancelLockpInventory(WmsOrderVo vo)
    throws Exception {
    InventoryExchangeFormVo formVo = new InventoryExchangeFormVo();
    if (ReflectUtil.hasField(WmsOrderVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setFrom(TargetTypeEnum.Normal);
    formVo.setTo(TargetTypeEnum.Normal);
    formVo.setFormNum(vo.getWoNumber());
    formVo.setDocumentType("销售出库单");
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("出仓库 为空");
    }
    formVo.setFromStockId(vo.getWid());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("入仓库 为空");
    }
    formVo.setToStockId(vo.getWid());
    formVo.setModel(PatternEnum.FIFO);
    for (WmsOrderItemItemVo wmsOrderItem : vo.getProductInfo()) {
      SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
      inventoryItem.setId(wmsOrderItem.getProductId());
      InventoryExchangeVo exchangeItem = new InventoryExchangeVo();
      exchangeItem.setItem(inventoryItem);
      exchangeItem.setQty(
        String.valueOf(wmsOrderItem.getCount()).equals("null")
          ? BigDecimal.valueOf(0)
          : BigDecimal.valueOf(wmsOrderItem.getCount())
      );
      Map<Long, Integer> binIds = new HashMap<>();
      binIds.put(
        wmsOrderItem.getWhbId(),
        Integer.parseInt(
          String.valueOf(wmsOrderItem.getCount()).equals("null")
            ? "0"
            : String.valueOf(wmsOrderItem.getCount())
        )
      );
      exchangeItem.setFromBinIds(binIds);
      Map<Long, Integer> toBinIds = new HashMap<>();
      toBinIds.put(
        wmsOrderItem.getWhbId(),
        Integer.parseInt(
          String.valueOf(wmsOrderItem.getCount()).equals("null")
            ? "0"
            : String.valueOf(wmsOrderItem.getCount())
        )
      );
      exchangeItem.setToBinIds(toBinIds);
      exchangeItem.setFromBinIdsType(TargetTypeEnum.Lock);
      exchangeItem.setToBinIdsType(TargetTypeEnum.Normal);
      exchangeItem.setCustomId(vo.getId());
      exchangeItem.setCustomBdId(wmsOrderItem.getId());
      formVo.add(exchangeItem);
    }
    return formVo;
  }

  /**
   * 订单（从锁定库存出库）
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了订单（从锁定库存出库）操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void lockStockOut(Long id) throws Exception {
    WmsOrderVo vo = getVoById(id);
    InventoryOutboundFormVo formVo = prepareLockStockOut(vo);
    inventoryBusinessService.outbound(formVo);
    // 更新成功状态
    WmsOrder updateStatusEntity = new WmsOrder();
    updateStatusEntity.setId(id);
    updateStatusEntity.setStatus("3");
    updateById(updateStatusEntity);
  }

  /**
   * 准备用于 订单（从锁定库存出库） 的参数
   */
  protected InventoryOutboundFormVo prepareLockStockOut(WmsOrderVo vo)
    throws Exception {
    if (!"2".equals(vo.getStatus())) {
      throw new Exception("当前单据状态不可进行此操作！");
    }
    InventoryOutboundFormVo formVo = new InventoryOutboundFormVo();
    if (ReflectUtil.hasField(WmsOrderVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setFrom(TargetTypeEnum.Lock);
    formVo.setFormNum(vo.getWoNumber());
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("仓库 为空");
    }
    formVo.setStockId(vo.getWid());
    formVo.setModel(PatternEnum.FIFO);
    for (WmsOrderItemItemVo wmsOrderItem : vo.getProductInfo()) {
      SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
      inventoryItem.setId(wmsOrderItem.getProductId());
      InventoryOutboundVo outboundItem = new InventoryOutboundVo();
      outboundItem.setItem(inventoryItem);
      outboundItem.setQty(
        String.valueOf(wmsOrderItem.getCount()).equals("null")
          ? BigDecimal.valueOf(0)
          : BigDecimal.valueOf(wmsOrderItem.getCount())
      );
      Map<Long, Integer> binIds = new HashMap<>();
      binIds.put(
        wmsOrderItem.getWhbId(),
        Integer.parseInt(
          String.valueOf(wmsOrderItem.getCount()).equals("null")
            ? "0"
            : String.valueOf(wmsOrderItem.getCount())
        )
      );
      outboundItem.setBinIds(binIds);
      outboundItem.setFromBinIdsType(TargetTypeEnum.Lock);
      outboundItem.setCustomId(vo.getId());
      outboundItem.setCustomBdId(wmsOrderItem.getId());
      formVo.add(outboundItem);
    }
    return formVo;
  }

  /**
   * 订单锁库存（锁库存_即时）
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了订单锁库存（锁库存_即时）操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void locksInventory(Long id) throws Exception {
    WmsOrderVo vo = getVoById(id);
    InventoryExchangeFormVo formVo = prepareLocksInventory(vo);
    inventoryBusinessService.exchange(formVo);
    // 更新成功状态
    WmsOrder updateStatusEntity = new WmsOrder();
    updateStatusEntity.setId(id);
    updateStatusEntity.setStatus("1");
    updateById(updateStatusEntity);
  }

  /**
   * 准备用于 订单锁库存（锁库存_即时） 的参数
   */
  protected InventoryExchangeFormVo prepareLocksInventory(WmsOrderVo vo)
    throws Exception {
    if (!"1".equals(vo.getStatus())) {
      throw new Exception("当前单据状态不可进行此操作！");
    }
    InventoryExchangeFormVo formVo = new InventoryExchangeFormVo();
    if (ReflectUtil.hasField(WmsOrderVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setFrom(TargetTypeEnum.Normal);
    formVo.setTo(TargetTypeEnum.Lock);
    formVo.setFormNum(vo.getWoNumber());
    formVo.setDocumentType("销售出库单");
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("出仓库 为空");
    }
    formVo.setFromStockId(vo.getWid());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("入仓库 为空");
    }
    formVo.setToStockId(vo.getWid());
    formVo.setModel(PatternEnum.FIFO);
    for (WmsOrderItemItemVo wmsOrderItem : vo.getProductInfo()) {
      SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
      inventoryItem.setId(wmsOrderItem.getProductId());
      InventoryExchangeVo exchangeItem = new InventoryExchangeVo();
      exchangeItem.setItem(inventoryItem);
      exchangeItem.setQty(
        String.valueOf(wmsOrderItem.getCount()).equals("null")
          ? BigDecimal.valueOf(0)
          : BigDecimal.valueOf(wmsOrderItem.getCount())
      );
      exchangeItem.setCustomId(vo.getId());
      exchangeItem.setCustomBdId(wmsOrderItem.getId());
      formVo.add(exchangeItem);
    }
    return formVo;
  }

  /**
   * 订单锁库存（锁库存_仓位）
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了订单锁库存（锁库存_仓位）操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void lockpInventory(Long id) throws Exception {
    WmsOrderVo vo = getVoById(id);
    InventoryExchangeFormVo formVo = prepareLockpInventory(vo);
    inventoryBusinessService.exchange(formVo);
    // 更新成功状态
    WmsOrder updateStatusEntity = new WmsOrder();
    updateStatusEntity.setId(id);
    updateStatusEntity.setStatus("2");
    updateById(updateStatusEntity);
  }

  /**
   * 准备用于 订单锁库存（锁库存_仓位） 的参数
   */
  protected InventoryExchangeFormVo prepareLockpInventory(WmsOrderVo vo)
    throws Exception {
    if (!"1".equals(vo.getStatus())) {
      throw new Exception("当前单据状态不可进行此操作！");
    }
    InventoryExchangeFormVo formVo = new InventoryExchangeFormVo();
    if (ReflectUtil.hasField(WmsOrderVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setFrom(TargetTypeEnum.Normal);
    formVo.setTo(TargetTypeEnum.Normal);
    formVo.setFormNum(vo.getWoNumber());
    formVo.setDocumentType("销售出库单");
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("出仓库 为空");
    }
    formVo.setFromStockId(vo.getWid());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("入仓库 为空");
    }
    formVo.setToStockId(vo.getWid());
    formVo.setModel(PatternEnum.FIFO);
    for (WmsOrderItemItemVo wmsOrderItem : vo.getProductInfo()) {
      SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
      inventoryItem.setId(wmsOrderItem.getProductId());
      InventoryExchangeVo exchangeItem = new InventoryExchangeVo();
      exchangeItem.setItem(inventoryItem);
      exchangeItem.setQty(
        String.valueOf(wmsOrderItem.getCount()).equals("null")
          ? BigDecimal.valueOf(0)
          : BigDecimal.valueOf(wmsOrderItem.getCount())
      );
      Map<Long, Integer> binIds = new HashMap<>();
      binIds.put(
        wmsOrderItem.getWhbId(),
        Integer.parseInt(
          String.valueOf(wmsOrderItem.getCount()).equals("null")
            ? "0"
            : String.valueOf(wmsOrderItem.getCount())
        )
      );
      exchangeItem.setFromBinIds(binIds);
      Map<Long, Integer> toBinIds = new HashMap<>();
      toBinIds.put(
        wmsOrderItem.getWhbId(),
        Integer.parseInt(
          String.valueOf(wmsOrderItem.getCount()).equals("null")
            ? "0"
            : String.valueOf(wmsOrderItem.getCount())
        )
      );
      exchangeItem.setToBinIds(toBinIds);
      exchangeItem.setFromBinIdsType(TargetTypeEnum.Normal);
      exchangeItem.setToBinIdsType(TargetTypeEnum.Lock);
      exchangeItem.setCustomId(vo.getId());
      exchangeItem.setCustomBdId(wmsOrderItem.getId());
      formVo.add(exchangeItem);
    }
    return formVo;
  }

  /**
   * 撤销到锁定
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了撤销到锁定操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void cancelpWarehousing(Long id) throws Exception {
    WmsOrderVo vo = getVoById(id);
    InventoryOutboundFormVo formVo = prepareCancelpWarehousing(vo);
    inventoryBusinessService.outbound(formVo);
    // 更新成功状态
    WmsOrder updateStatusEntity = new WmsOrder();
    updateStatusEntity.setId(id);
    updateStatusEntity.setStatus("3");
    updateById(updateStatusEntity);
  }

  /**
   * 准备用于 撤销到锁定 的参数
   */
  protected InventoryOutboundFormVo prepareCancelpWarehousing(WmsOrderVo vo)
    throws Exception {
    if (!"3".equals(vo.getStatus())) {
      throw new Exception("当前单据状态不可进行此操作！");
    }
    InventoryOutboundFormVo formVo = new InventoryOutboundFormVo();
    if (ReflectUtil.hasField(WmsOrderVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setOperate("撤消出库");
    formVo.setReverseQtySign(true);
    formVo.setSupportNegative(true);
    formVo.setFrom(TargetTypeEnum.Lock);
    formVo.setFormNum(vo.getOrderNumber());
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("仓库 为空");
    }
    formVo.setStockId(vo.getWid());
    formVo.setModel(PatternEnum.FIFO);
    for (WmsOrderItemItemVo wmsOrderItem : vo.getProductInfo()) {
      SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
      inventoryItem.setId(wmsOrderItem.getProductId());
      InventoryOutboundVo outboundItem = new InventoryOutboundVo();
      outboundItem.setItem(inventoryItem);
      outboundItem.setQty(
        String.valueOf(wmsOrderItem.getCount()).equals("null")
          ? BigDecimal.valueOf(0)
          : BigDecimal.valueOf(wmsOrderItem.getCount())
      );
      Map<Long, Integer> binIds = new HashMap<>();
      binIds.put(
        wmsOrderItem.getWhbId(),
        Integer.parseInt(
          String.valueOf(wmsOrderItem.getCount()).equals("null")
            ? "0"
            : String.valueOf(wmsOrderItem.getCount())
        )
      );
      outboundItem.setBinIds(binIds);
      outboundItem.setFromBinIdsType(TargetTypeEnum.Lock);
      outboundItem.setCustomId(vo.getId());
      outboundItem.setCustomBdId(wmsOrderItem.getId());
      formVo.add(outboundItem);
    }
    return formVo;
  }

  /**
   * 同步当天数据
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了同步当天数据操作"
  )
  @Transactional(rollbackFor = Exception.class)
  @Override
  public void syncWms() throws Exception {
    executeScriptEngine.callJsInResource(
      "scripts/WmsOrder_syncWms.js",
      null,
      null,
      this
    );
  }

  /**
   * 撤销库存
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了撤销库存操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void cancelWarehousing(Long id) throws Exception {
    WmsOrderVo vo = getVoById(id);
    InventoryOutboundFormVo formVo = prepareCancelWarehousing(vo);
    inventoryBusinessService.outbound(formVo);
    // 更新成功状态
    WmsOrder updateStatusEntity = new WmsOrder();
    updateStatusEntity.setId(id);
    updateStatusEntity.setStatus("3");
    updateById(updateStatusEntity);
  }

  /**
   * 准备用于 撤销库存 的参数
   */
  protected InventoryOutboundFormVo prepareCancelWarehousing(WmsOrderVo vo)
    throws Exception {
    if (!"3".equals(vo.getStatus())) {
      throw new Exception("当前单据状态不可进行此操作！");
    }
    InventoryOutboundFormVo formVo = new InventoryOutboundFormVo();
    if (ReflectUtil.hasField(WmsOrderVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setOperate("撤消出库");
    formVo.setReverseQtySign(true);
    formVo.setSupportNegative(true);
    formVo.setFrom(TargetTypeEnum.Normal);
    formVo.setFormNum(vo.getWoNumber());
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("仓库 为空");
    }
    formVo.setStockId(vo.getWid());
    formVo.setModel(PatternEnum.FIFO);
    for (WmsOrderItemItemVo wmsOrderItem : vo.getProductInfo()) {
      SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
      inventoryItem.setId(wmsOrderItem.getProductId());
      InventoryOutboundVo outboundItem = new InventoryOutboundVo();
      outboundItem.setItem(inventoryItem);
      outboundItem.setQty(
        String.valueOf(wmsOrderItem.getCount()).equals("null")
          ? BigDecimal.valueOf(0)
          : BigDecimal.valueOf(wmsOrderItem.getCount())
      );
      Map<Long, Integer> binIds = new HashMap<>();
      binIds.put(
        wmsOrderItem.getWhbId(),
        Integer.parseInt(
          String.valueOf(wmsOrderItem.getCount()).equals("null")
            ? "0"
            : String.valueOf(wmsOrderItem.getCount())
        )
      );
      outboundItem.setBinIds(binIds);
      outboundItem.setFromBinIdsType(TargetTypeEnum.Normal);
      outboundItem.setCustomId(vo.getId());
      outboundItem.setCustomBdId(wmsOrderItem.getId());
      formVo.add(outboundItem);
    }
    return formVo;
  }

  /**
   * 根据时间同步领星销售出库单
   */
  /**
   * 根据时间同步领星销售出库单表单确定操作
   */
  @Override
  public void syncDateWmsConfirm(JSONObject data) throws Exception {
    executeScriptEngine.callJsInResource(
      "scripts/WmsOrder_syncDateWms_confirm.js",
      data,
      this
    );
  }

  /**
   * 批量出库
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了批量出库操作"
  )
  @Override
  public void batchStockOut(List<Long> ids) throws Exception {
    if (wmsOrderBatchStockOutAction == null) {
      throw new Exception("此操作当前不可用");
    }
    wmsOrderBatchStockOutAction.run(ids);
  }

  /**
   * 扣库存
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了扣库存操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void subInventory(Long id) throws Exception {
    WmsOrderVo vo = getVoById(id);
    InventoryOutboundFormVo formVo = prepareSubInventory(vo);
    inventoryBusinessService.outbound(formVo);
  }

  /**
   * 准备用于 扣库存 的参数
   */
  protected InventoryOutboundFormVo prepareSubInventory(WmsOrderVo vo)
    throws Exception {
    InventoryOutboundFormVo formVo = new InventoryOutboundFormVo();
    if (ReflectUtil.hasField(WmsOrderVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setFrom(TargetTypeEnum.Lock);
    formVo.setFormNum(vo.getOrderNumber());
    formVo.setDocumentType("订单管理");
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("仓库 为空");
    }
    formVo.setStockId(vo.getWid());
    formVo.setModel(PatternEnum.FIFO);
    for (WmsOrderItemItemVo wmsOrderItem : vo.getProductInfo()) {
      SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
      inventoryItem.setId(wmsOrderItem.getProductId());
      InventoryOutboundVo outboundItem = new InventoryOutboundVo();
      outboundItem.setItem(inventoryItem);
      outboundItem.setQty(
        String.valueOf(wmsOrderItem.getCount()).equals("null")
          ? BigDecimal.valueOf(0)
          : BigDecimal.valueOf(wmsOrderItem.getCount())
      );
      Map<Long, Integer> binIds = new HashMap<>();
      binIds.put(
        wmsOrderItem.getWhbId(),
        Integer.parseInt(
          String.valueOf(wmsOrderItem.getCount()).equals("null")
            ? "0"
            : String.valueOf(wmsOrderItem.getCount())
        )
      );
      outboundItem.setBinIds(binIds);
      outboundItem.setFromBinIdsType(TargetTypeEnum.Lock);
      outboundItem.setCustomId(vo.getId());
      outboundItem.setCustomBdId(wmsOrderItem.getId());
      formVo.add(outboundItem);
    }
    return formVo;
  }

  /**
   * 直接扣减库存
   */
  @DataActivity(
    action = SysDataActivityAction.Other,
    message = "%s执行了直接扣减库存操作"
  )
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void stockOut(Long id) throws Exception {
    WmsOrderVo vo = getVoById(id);
    InventoryOutboundFormVo formVo = prepareStockOut(vo);
    inventoryBusinessService.outbound(formVo);
    // 更新成功状态
    WmsOrder updateStatusEntity = new WmsOrder();
    updateStatusEntity.setId(id);
    updateStatusEntity.setStatus("5");
    updateById(updateStatusEntity);
  }

  /**
   * 准备用于 直接扣减库存 的参数
   */
  protected InventoryOutboundFormVo prepareStockOut(WmsOrderVo vo)
    throws Exception {
    if (!"3".equals(vo.getStatus())) {
      throw new Exception("当前单据状态不可进行此操作！");
    }
    InventoryOutboundFormVo formVo = new InventoryOutboundFormVo();
    if (ReflectUtil.hasField(WmsOrderVo.class, "remark")) {
      formVo.setRemark(Convert.toStr(ReflectUtil.getFieldValue(vo, "remark")));
    }
    formVo.setFrom(TargetTypeEnum.Normal);
    formVo.setFormNum(vo.getOrderNumber());
    formVo.setDocumentType("销售出库");
    if (ObjectUtils.isEmpty(vo.getCreateUser())) {
      throw new Exception("关联制单人为空");
    }
    formVo.setFormOperator(vo.getCreateUser().toString());
    if (ObjectUtils.isEmpty(vo.getWid())) {
      throw new Exception("仓库 为空");
    }
    formVo.setStockId(vo.getWid());
    formVo.setModel(PatternEnum.FIFO);
    for (WmsOrderItemItemVo wmsOrderItem : vo.getProductInfo()) {
      SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
      inventoryItem.setId(wmsOrderItem.getProductId());
      InventoryOutboundVo outboundItem = new InventoryOutboundVo();
      outboundItem.setItem(inventoryItem);
      outboundItem.setQty(
        String.valueOf(wmsOrderItem.getCount()).equals("null")
          ? BigDecimal.valueOf(0)
          : BigDecimal.valueOf(wmsOrderItem.getCount())
      );
      Map<Long, Integer> binIds = new HashMap<>();
      binIds.put(
        wmsOrderItem.getWhbId(),
        Integer.parseInt(
          String.valueOf(wmsOrderItem.getCount()).equals("null")
            ? "0"
            : String.valueOf(wmsOrderItem.getCount())
        )
      );
      outboundItem.setBinIds(binIds);
      outboundItem.setFromBinIdsType(TargetTypeEnum.Normal);
      outboundItem.setCustomId(vo.getId());
      outboundItem.setCustomBdId(wmsOrderItem.getId());
      formVo.add(outboundItem);
    }
    return formVo;
  }

  /**
   * 视图选项卡标题上显示计数
   */

  @Override
  public Map getTabHeaderShowTotal() {
    WmsOrderSearchParamPo search = new WmsOrderSearchParamPo();
    return MapUtil
      .builder()
      .put("WmsOrder", this.baseMapper.wmsOrderCount(search))
      .build();
  }

  /**
   * 销售出库单
   */
  @Override
  public List<WmsOrderItemVo> wmsOrder(WmsOrderSearchParamPo search) {
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    return this.baseMapper.wmsOrder(search);
  }

  /**
   * 销售出库单分页
   */
  @Override
  public Page<WmsOrderItemVo> wmsOrderPage(WmsOrderSearchParamPo search) {
    Page<WmsOrderItemVo> wmsOrderPage = new Page<>();
    if (
      Objects.nonNull(search.getWfStatus()) &&
      StringUtils.hasText(search.getFormName())
    ) {
      List<WorkFlow> workFlowList = workFlowService.queryWfListByStatus(
        search.getWfStatus(),
        search.getFormName()
      );
      if (CollectionUtils.isEmpty(workFlowList)) {
        return wmsOrderPage;
      }
      List<Long> ids = workFlowList
        .stream()
        .map(WorkFlow::getRecordId)
        .collect(Collectors.toList());
      if (CollectionUtils.isEmpty(ids)) {
        return wmsOrderPage;
      }
      search.setSelectedIds(ids);
    }
    search.initSort("t.id desc", "t.", SORT_FIELD_MAP);
    wmsOrderPage =
      this.baseMapper.wmsOrderPage(
          search.toPage(this.baseMapper.wmsOrderCount(search)),
          search
        );
    if (
      search.getFillParts() == null ||
      search.getFillParts().contains("productInfo")
    ) {
      fillPartOfProductInfo(
        wmsOrderPage.getRecords(),
        search.toChildSort("productInfo")
      );
    }
    List<Long> recordIds = wmsOrderPage
      .getRecords()
      .stream()
      .map(WmsOrderItemVo::getId)
      .collect(Collectors.toList());
    if (CollectionUtils.isEmpty(recordIds)) {
      return wmsOrderPage;
    }
    List<WorkFlow> workFlows = workFlowService.queryWfList(
      recordIds,
      Collections.singletonList(search.getFormName())
    );
    if (CollectionUtils.isEmpty(workFlows)) {
      return wmsOrderPage;
    }
    Map<Long, Integer> flowMap = workFlows
      .stream()
      .collect(Collectors.toMap(WorkFlow::getRecordId, WorkFlow::getWfStatus));
    wmsOrderPage
      .getRecords()
      .stream()
      .forEach(item -> {
        if (!flowMap.containsKey(item.getId())) {
          return;
        }
        item.setWfStatus(flowMap.get(item.getId()));
      });

    return wmsOrderPage;
  }

  /**
   * 查询销售出库单最后更新时间
   * @param search 查询条件
   * @return 销售出库单最后更新时间
   */
  @Override
  public Date wmsOrderLastUpdateTime(WmsOrderSearchParamPo search) {
    return this.baseMapper.wmsOrderLastUpdateTime(search);
  }
}
